function FetchBuilder()
{

this.AddAttribute = addAttribute;
this.AddLinkEntity = addLinkEntity;
this.ClearSorting = clearSorting;
this.GetAttributeInfo = getAttributeInfo;
this.GetAttributeInfos = getAttributeInfos;
this.GetPrimaryEntityAttributeAliases = getPrimaryEntityAttributeAliases;
this.GetPrimaryEntityName = getPrimaryEntityName;
this.GetSecondaryEntityName = getSecondaryEntityName;
this.GetSecondaryEntityString = getSecondaryEntityString;
this.GetSortNode = getSortNode;
this.GetXml = getXml;
this.IsSortAttribute = isSortAttribute;
this.LoadXml = loadXml;
this.RemoveAttribute = removeAttribute;
this.SetPrimaryEntity = setPrimaryEntity;
this.SetSecondaryEntity = setSecondaryEntity;
this.SetSortAttribute = setSortAttribute;


var _oFetchXml = null;



function addAttribute(sEntityAlias, sAttributeName)
{
var oEntityNode = getEntityNode(sEntityAlias);

var oAttributeNode = oEntityNode.selectSingleNode(formatString("attribute[@name = '{0}']", sAttributeName));
var sAttributeAlias;
if (IsNull(oAttributeNode))
{

sAttributeAlias = getAttributeAlias(sEntityAlias, sAttributeName);


oAttributeNode = _oFetchXml.createElement("attribute");
oAttributeNode.setAttribute("name", sAttributeName);
oAttributeNode.setAttribute("alias", sAttributeAlias);
oEntityNode.appendChild(oAttributeNode);
}
else
{
sAttributeAlias = oAttributeNode.getAttribute("alias");
}


return sAttributeAlias;
}

function addLinkEntity(sName, sAlias, sFrom, sTo, sParentAlias)
{

var oParentNode = getEntityNode(sParentAlias);


var oLinkEntityNode = oParentNode.selectSingleNode(formatString("link-entity[@alias = '{0}']", sAlias));
if (IsNull(oLinkEntityNode))
{
oLinkEntityNode = createLinkEntityNode(sName, sFrom, sTo, sAlias);
oParentNode.appendChild(oLinkEntityNode);
}
}

function clearSorting()
{
var oSortNode = getSortNode();
if (!IsNull(oSortNode))
{
oSortNode.parentNode.removeChild(oSortNode);
}
}

function createLinkEntityNode(sName, sFrom, sTo, sAlias)
{
var oLinkEntityNode = _oFetchXml.createElement("link-entity");
oLinkEntityNode.setAttribute("name", sName)
oLinkEntityNode.setAttribute("from", sFrom)
oLinkEntityNode.setAttribute("to", sTo)
if (!IsNull(sAlias))
{
oLinkEntityNode.setAttribute("alias", sAlias);
}
oLinkEntityNode.setAttribute("link-type", "outer");

return oLinkEntityNode;
}

function getAttributeInfos(saAttributeAliases)
{
var oaAttributeInfos = new Array();

for (var i = 0; i < saAttributeAliases.length; i++)
{
var oAttributeInfo = getAttributeInfo(saAttributeAliases[i]);
var sEntityAlias = IsNull(oAttributeInfo.EntityAlias) ? "" : oAttributeInfo.EntityAlias;
if (IsNull(oaAttributeInfos[sEntityAlias]))
{
oaAttributeInfos[sEntityAlias] = new Array();
}
oaAttributeInfos[sEntityAlias][oAttributeInfo.Attribute] = "";
}

return oaAttributeInfos;
}

function getAttributeInfo(sAttributeAlias)
{

var oAttributeNode = getAttributeNode(sAttributeAlias);


var oAttribute = new Object();
oAttribute.Entity = oAttributeNode.parentNode.getAttribute("name");
oAttribute.EntityAlias = oAttributeNode.parentNode.getAttribute("alias");
oAttribute.Attribute = oAttributeNode.getAttribute("name");
return oAttribute;
}

function getAttributeAlias(sEntityAlias, sAttributeName)
{
return (IsNull(sEntityAlias) || sEntityAlias.length == 0) ? sAttributeName : formatString("{0}_{1}", sEntityAlias, sAttributeName);
}

function getAttributeNode(sAttributeAlias)
{
return _oFetchXml.selectSingleNode(formatString("//attribute[@alias = '{0}']", sAttributeAlias));
}

function getEntityNode(sAlias)
{
return (sAlias.length == 0) ? getPrimaryEntityNode() : _oFetchXml.selectSingleNode(formatString("//link-entity[@alias = '{0}']", sAlias));
}

function getLinkEntityString(oLinkEntityNode)
{
return formatString("{0};{1};{2}",
oLinkEntityNode.getAttribute("name"),
oLinkEntityNode.getAttribute("from"),
oLinkEntityNode.getAttribute("to"));
}

function getPrimaryEntityAttributeAliases()
{
var saAttributeAliases = new Array();
var oaAttributes = getPrimaryEntityNode().selectNodes("attribute");

for (var i = 0; i < oaAttributes.length; i++)
{
saAttributeAliases.push(oaAttributes[i].getAttribute("alias"));
}

return saAttributeAliases;
}

function getPrimaryEntityName()
{
var oPrimaryEntityNode = getPrimaryEntityNode();
return IsNull(oPrimaryEntityNode) ? null : oPrimaryEntityNode.getAttribute("name");
}

function getPrimaryEntityNode()
{
return _oFetchXml.selectSingleNode("/fetch/entity");
}

function getSecondaryEntityName()
{
var oSecondaryEntityNode = getSecondaryEntityNode();
return IsNull(oSecondaryEntityNode) ? null : oSecondaryEntityNode.getAttribute("name");
}

function getSecondaryEntityNode()
{
return _oFetchXml.selectSingleNode("/fetch/entity//link-entity[@secondary = '1']");
}

function getSecondaryEntityString()
{
var oSecondaryEntityNode = getSecondaryEntityNode();
if (IsNull(oSecondaryEntityNode))
{
return null;
}



if (isLinkEntityNode(oSecondaryEntityNode.parentNode))
{
var oIntersectEntityNode = oSecondaryEntityNode.parentNode;
return formatString(
"{0};;;true;{1};{2};{3}",
oSecondaryEntityNode.getAttribute("name"),
oIntersectEntityNode.getAttribute("name"),
oIntersectEntityNode.getAttribute("from"),
oSecondaryEntityNode.getAttribute("from"));
}
else
{
return getLinkEntityString(oSecondaryEntityNode);
}
}

function getSortNode()
{
return getPrimaryEntityNode().selectSingleNode("order");
}

function getXml()
{

var oReturnFetchXml = loadXmlDocument(_oFetchXml.xml);


var oaAttributeNodes = oReturnFetchXml.selectNodes("//attribute");
for (var i = 0; i < oaAttributeNodes.length; i++)
{
oaAttributeNodes[i].removeAttribute("alias");
}


return oReturnFetchXml;
}

function isLinkEntityNode(oNode)
{
return (oNode.nodeName == "link-entity");
}

function isSortAttribute(sAttributeAlias)
{
var oSortNode = getSortNode();
return (!IsNull(oSortNode) && oSortNode.getAttribute("attribute") == sAttributeAlias);
}

function loadXml(oFetchXml)
{

_oFetchXml = (IsNull(oFetchXml)) ? loadXmlDocument("<fetch version=\"1.0\" output-format=\"xml-platform\" mapping=\"logical\" distinct=\"false\" />") : oFetchXml;


if (!IsNull(oFetchXml))
{
var oaAttributeNodes = _oFetchXml.selectNodes("//attribute");
for (var i = 0; i < oaAttributeNodes.length; i++)
{
var oAttributeNode = oaAttributeNodes[i];
var sAttributeAlias = getAttributeAlias(
oAttributeNode.parentNode.getAttribute("alias"),
oAttributeNode.getAttribute("name"))

oAttributeNode.setAttribute("alias", sAttributeAlias);
}
}
}

function removeAttribute(sAttributeAlias)
{

var oAttributeNode = getAttributeNode(sAttributeAlias);


if (IsNull(oAttributeNode))
{
return;
}


var oEntityNode = oAttributeNode.parentNode;


oEntityNode.removeChild(oAttributeNode);




if (oEntityNode.childNodes.length == 0 && isLinkEntityNode(oEntityNode) && IsNull(oEntityNode.getAttribute("secondary")))
{
oEntityNode.parentNode.removeChild(oEntityNode);
}


var oSortNode = getSortNode();
if (!IsNull(oSortNode) && oSortNode.getAttribute("attribute") == sAttributeAlias)
{
oEntityNode.removeChild(oSortNode);
}
}

function setPrimaryEntity(sEntityName)
{

if (IsNull(sEntityName) || sEntityName.length == 0)
{
return;
}



var oRootNode = _oFetchXml.selectSingleNode("/fetch");
var oPrimaryEntityNode = getPrimaryEntityNode();
if (IsNull(oPrimaryEntityNode) || oPrimaryEntityNode.getAttribute("name") != sEntityName)
{



if (!IsNull(oPrimaryEntityNode))
{
oRootNode.selectNodes("*").removeAll();
}


var oNewPrimaryEntityNode = _oFetchXml.createElement("entity");
oNewPrimaryEntityNode.setAttribute("name", sEntityName)


oRootNode.appendChild(oNewPrimaryEntityNode);
}
}

function setSecondaryEntity(sEntityString)
{









var saEntityStringElements = null;
var bIsIntersect = false;
var sEntityName = null;
if (!IsNull(sEntityString))
{
saEntityStringElements = sEntityString.split(";");
bIsIntersect = saEntityStringElements.length > 3;
sEntityName = saEntityStringElements[0];
}




var oPrimaryEntityNode = getPrimaryEntityNode();
var sSecondaryEntityString = getSecondaryEntityString();
var bSecondaryEntityChanged = (sSecondaryEntityString != sEntityString);
if (!IsNull(sSecondaryEntityString))
{


if (IsNull(sEntityName) || sEntityName.length == 0 || bSecondaryEntityChanged)
{




var oSecondaryEntityNode = getSecondaryEntityNode();
if (isLinkEntityNode(oSecondaryEntityNode.parentNode))
{
oSecondaryEntityNode = oSecondaryEntityNode.parentNode;
}

oPrimaryEntityNode.removeChild(oSecondaryEntityNode);
}
}




if (!IsNull(sEntityName) && sEntityName.length > 0 && bSecondaryEntityChanged)
{
var oNewSecondaryEntityNode;
var sSecondaryEntityAlias = formatString("{0}1", sEntityName);
if (bIsIntersect)
{


var sIntersectEntityName = saEntityStringElements[4];
var sIntersectAttributeName = saEntityStringElements[5];
var oIntersectEntityNode = createLinkEntityNode(sIntersectEntityName, sIntersectAttributeName, sIntersectAttributeName, null);
oPrimaryEntityNode.appendChild(oIntersectEntityNode);



var sSecondaryEntityJoinAttribute = saEntityStringElements[6];
oNewSecondaryEntityNode = createLinkEntityNode(sEntityName, sSecondaryEntityJoinAttribute, sSecondaryEntityJoinAttribute, sSecondaryEntityAlias);
oIntersectEntityNode.appendChild(oNewSecondaryEntityNode);
}
else
{

var sFromAttribute = saEntityStringElements[1];
var sToAttribute = saEntityStringElements[2];
oNewSecondaryEntityNode = createLinkEntityNode(sEntityName, sFromAttribute, sToAttribute, sSecondaryEntityAlias);


oPrimaryEntityNode.appendChild(oNewSecondaryEntityNode);
}


oNewSecondaryEntityNode.setAttribute("secondary", 1)
}
}

function setSortAttribute(sAttributeName, bDescending)
{
var oSortNode = getSortNode();
var oPrimaryEntityNode = getPrimaryEntityNode();
if (!IsNull(oSortNode))
{
oPrimaryEntityNode.removeChild(oSortNode);
}

oSortNode = _oFetchXml.createElement("order");
oSortNode.setAttribute("attribute", sAttributeName);
oSortNode.setAttribute("descending", bDescending);
oPrimaryEntityNode.appendChild(oSortNode);
}
}
